package com.tj.api.rest.trade;

import com.fqgj.base.services.redis.RedisClient;
import com.fqgj.common.api.annotations.ParamsValidate;
import com.fqgj.common.utils.CollectionUtils;
import com.fqgj.log.util.Constants;
import com.tj.api.annotations.VisitorAccessible;
import com.tj.bo.common.conf.api.ApiResponse;
import com.tj.bo.common.conf.config.RedisConfigUtil;
import com.tj.bo.common.conf.constant.RedisKey;
import com.tj.bo.common.conf.enums.ProductEnum;
import com.tj.bo.common.conf.util.HttpUtil;
import com.tj.bo.common.conf.vo.MarketTimePrice;
import com.tj.bo.user.client.UserRegisterService;
import com.tj.bo.user.client.vo.input.UserChannelRepairInput;
import com.tj.template.application.trade.OrderApplication;
import com.tj.template.application.trade.input.*;
import com.tj.template.application.trade.output.*;
import com.tj.template.application.vo.Bucket;
import com.tj.template.config.vo.RequestBasicInfo;
import com.tj.template.config.vo.RequestLocalInfo;
import com.tj.template.config.vo.UserAccessInfo;
import org.apache.logging.log4j.ThreadContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

/**
 * @program: binary-option
 * @description
 * @author: binary
 * @create: 2020-06-10 18:14
 **/
@RestController
@RequestMapping("/binary/trade")
public class TradeController {
    private static final Logger LOGGER = LoggerFactory.getLogger(TradeController.class);

    @Autowired
    private OrderApplication orderApplication;

    @Autowired
    private RedisClient redisClient;

    @Autowired
    private RedisConfigUtil redisDbConfigUtil;

    @Autowired
    private UserRegisterService userRegisterService;

    /**
     * 下单
     *
     * @param request
     * @return
     */
    @VisitorAccessible
    @ParamsValidate
    @RequestMapping(value = "/submit", method = RequestMethod.POST)
    public ApiResponse<CreateTradeResponse> submitOrder(HttpServletRequest request, @RequestBody @Valid CreateTradeRequest createTradeRequest) {
        String ip = HttpUtil.getIpAddr(request);

        CreateTradeResponse createTradeResponse = orderApplication.submitOrder(createTradeRequest, ip);

        //渠道号修复
        RequestBasicInfo requestBasicInfo = RequestLocalInfo.getRequestBasicInfo();
        UserAccessInfo userAccessInfo = RequestLocalInfo.getCurrentUser();
        UserChannelRepairInput userChannelRepairInput = new UserChannelRepairInput();
        userChannelRepairInput.setAppCode(requestBasicInfo.getAppCode());
        userChannelRepairInput.setUserCode(userAccessInfo == null ? null : userAccessInfo.getUserCode());
        userChannelRepairInput.setDeviceId(requestBasicInfo.getDeviceId());
        userChannelRepairInput.setChannel(requestBasicInfo.getChannel());
        userChannelRepairInput.setMessage(ThreadContext.get(Constants.TRACE_ID));
        userRegisterService.registerChannelRepairAsync(userChannelRepairInput);

        return new ApiResponse<>(createTradeResponse);
    }

    /**
     * 查询订单列表
     *
     * @param request
     * @return
     */
    @VisitorAccessible
    @ParamsValidate
    @RequestMapping(value = "/list", method = RequestMethod.POST)
    public ApiResponse<TradeListResponse> orderList(@RequestBody @Valid TradeListRequest request) {
        return new ApiResponse<>(orderApplication.orderList(request));
    }


    /**
     * 根据订单号查询订单详情
     *
     * @param request
     * @return
     */
    @VisitorAccessible
    @ParamsValidate
    @RequestMapping(value = "/detail", method = RequestMethod.POST)
    public ApiResponse<TradeInfoResponse> orderDetail(@RequestBody @Valid TradeDetailRequest request) {
        return new ApiResponse<>(orderApplication.orderDetail(request));
    }

    /**
     * 交易大盘数据
     *
     * @param request
     * @return
     */
    @VisitorAccessible
    @ParamsValidate
    @RequestMapping(value = "/market", method = RequestMethod.POST)
    //{"productCode":"F_GBP_USD","chartTime":180,"tradeType":0}
    public ApiResponse<MarketDataResponse> marketData(@RequestBody @Valid MarketDataRequest request) {
//        request.setNodeNum(180);
        MarketDataResponse marketDataResponse = null;
        marketDataResponse = marketDataV2(request).getData();
//        if (redisDbConfigUtil.isNewMarketData()) {
//        } else {
//            marketDataResponse = orderApplication.marketData(request);
//        }

        //渠道号修复
        RequestBasicInfo requestBasicInfo = RequestLocalInfo.getRequestBasicInfo();
        UserAccessInfo userAccessInfo = RequestLocalInfo.getCurrentUser();
        UserChannelRepairInput userChannelRepairInput = new UserChannelRepairInput();
        userChannelRepairInput.setAppCode(requestBasicInfo.getAppCode());
        userChannelRepairInput.setUserCode(userAccessInfo == null ? null : userAccessInfo.getUserCode());
        userChannelRepairInput.setDeviceId(requestBasicInfo.getDeviceId());
        userChannelRepairInput.setChannel(requestBasicInfo.getChannel());
        userChannelRepairInput.setMessage(ThreadContext.get(Constants.TRACE_ID));
        userRegisterService.registerChannelRepairAsync(userChannelRepairInput);

        return new ApiResponse<>(marketDataResponse);
    }

    @VisitorAccessible
    @ParamsValidate
    @RequestMapping(value = "/market/v3", method = RequestMethod.POST)
    public ApiResponse<MarketDataResponse> marketDataV3(@RequestBody @Valid MarketDataRequest request) {
        if (request.getChartTime() > 180) {
            return this.marketData(request);
        }
        MarketDataResponse marketDataResponse = orderApplication.marketData(request);
        //渠道号修复
        RequestBasicInfo requestBasicInfo = RequestLocalInfo.getRequestBasicInfo();
        UserAccessInfo userAccessInfo = RequestLocalInfo.getCurrentUser();
        UserChannelRepairInput userChannelRepairInput = new UserChannelRepairInput();
        userChannelRepairInput.setAppCode(requestBasicInfo.getAppCode());
        userChannelRepairInput.setUserCode(userAccessInfo == null ? null : userAccessInfo.getUserCode());
        userChannelRepairInput.setDeviceId(requestBasicInfo.getDeviceId());
        userChannelRepairInput.setChannel(requestBasicInfo.getChannel());
        userChannelRepairInput.setMessage(ThreadContext.get(Constants.TRACE_ID));
        userRegisterService.registerChannelRepairAsync(userChannelRepairInput);

        return new ApiResponse<>(marketDataResponse);
    }

    /**
     * 交易大盘数据
     *
     * @param request
     * @return
     */
    @VisitorAccessible
    @ParamsValidate
    @RequestMapping(value = "/market/v2", method = RequestMethod.POST)
    public ApiResponse<MarketDataResponse> marketDataV2(@RequestBody @Valid MarketDataRequest request) {
        long rightTime = System.currentTimeMillis();
        LOGGER.info("== mv2 start time==,rightTime:{}", rightTime);
        MarketDataResponse response = new MarketDataResponse();
        List<MarketTimePrice> marketProducts = new ArrayList<>();

        try {
            //额外增加10个节点的数据，调整大盘最左侧时间点
            int timeRange = request.getChartTime() * 1000 / request.getNodeNum();
            long leftTime = rightTime - (request.getNodeNum() + 10) * timeRange;

            //第一条数据是最老的数据
            Set<ZSetOperations.TypedTuple<Object>> openingPriceSet = redisClient.zRangeByScoreWithScores(RedisKey.ZSET_BINARY_OPTION_PRODUCT_KEY, leftTime, rightTime, request.getProductCode());
            LOGGER.info("== testMarket 查询redis获得数据数量 ==,leftTime:{},leftTime:{},timeRange:{},cnt:{}", leftTime, leftTime, timeRange, openingPriceSet.size());

            if (CollectionUtils.isEmpty(openingPriceSet)) {
                return new ApiResponse<>(response);
            }

            List<ZSetOperations.TypedTuple<Object>> openingPriceStrList = new ArrayList<>(openingPriceSet);

//            int nodeNum = 180;

            Bucket[] buckets = OrderApplication.test2(openingPriceStrList, rightTime, timeRange, request.getNodeNum());


            response = new MarketDataResponse();
            response.setRisingProbability("52%");
            response.setFallingProbability("48%");

            marketProducts = new ArrayList<>(request.getNodeNum());

            for (int i = 0, isize = buckets.length; i < isize; i++) {
                Bucket bucket = buckets[i];
                MarketTimePrice marketTimePrice = bucket.getMarketTimePrice();

                if (buckets[i].getCnt() == 0) {
                    marketTimePrice = bucket.getLastBucket().getMarketTimePrice();
                }


                marketProducts.add(new MarketTimePrice(marketTimePrice.getType(),
                        priceTailCulculator(buckets[i].getCnt() == 0 ? bucket.getLastBucket().getAvgPrice() : bucket.getAvgPrice(), request.getProductCode()),
                        bucket.getEndTime(),
                        marketTimePrice.getBusinessTime()
                ));
            }


            LOGGER.info("== marketProducts size ==,cnt:{}", marketProducts.size());
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("== testMarket exception  ==", e);
        }

        Collections.reverse(marketProducts);


//        LOGGER.info("== testMarket marketProducts 999 ==,startTime:{}, 0:{},end:{}", rightTime, marketProducts.get(0).getMarketTimestamp(), marketProducts.get(marketProducts.size() - 1).getMarketTimestamp());
        LOGGER.info("market cost B :{}", System.currentTimeMillis() - rightTime);
        return new ApiResponse<>(response.setMarketProducts(marketProducts));
    }

    public static void main(String[] args) {
        String c_btc_usd = priceTailCulculator(0.0127D, "C_BTC_USD");

        System.err.println(111);
    }

    public static String priceTailCulculator(Double originPrice, String productCode) {
        ProductEnum productEnum = ProductEnum.getEnumByProductCode(productCode);
        if (productEnum == null) {
            return originPrice.toString();
        }
        //四舍五入操作
        String price = new BigDecimal(originPrice).setScale(productEnum.getTailNum(), BigDecimal.ROUND_HALF_UP).toPlainString();
        return price;
    }


    /***
     * 开盘中的交易列表
     * @param request
     * @return
     */
    @VisitorAccessible
    @ParamsValidate
    @RequestMapping(value = "/opening/orders", method = RequestMethod.POST)
    public ApiResponse<OpeningTradeResponse> openingOrders(@RequestBody @Valid OpeningTradeRequest request) {
        return new ApiResponse<>(orderApplication.openingOrders(request));
    }

    /**
     * 轮询大盘数据
     *
     * @return
     */
    @VisitorAccessible
    @ParamsValidate
    @RequestMapping(value = "/query", method = RequestMethod.POST)
    public ApiResponse<MarketQueryResponse> queryMarket(@RequestBody @Valid MarketQueryRequest request) {
        return new ApiResponse<>(orderApplication.queryMarket(request));
    }


//    public static void main(String[] args) {
//        long a = 10 % 3;
//
//        System.err.println(11);
//    }

}
